package org.example.utils;

/**
 * @BelongsProject：test
 * @CreateTime 2024-05-21-20:37
 * @Author SweetPig
 */
public class SnowFlake {
    // 起始时间 2020/1/1 00:00:00
    private final long startTime = 1577808000000L;

    // 序列段
    private long sequenceId = 0L;
    // 序列段位数
    private final long sequenceBits = 12L;
    // 序列段掩码
    private final long sequenceMask = ~(-1L << sequenceBits);
    // 序列段最大值
    private final long maxSequence = ~(-1L << sequenceBits);

    // 工作机器id
    private long workerId = 0L;
    // 工作机器位数
    private final long workerBits = 10L;
    // 工作机器掩码
    private final long workerMask = (~(-1L << (sequenceBits + workerBits))) ^ sequenceMask;
    // 工作机器最大值
    private final long maxWorker = ~(-1L << workerBits);

    // 时间戳
    private long timestamp = 0L;
    // 时间戳位数
    private final long timestampBits = 41L;
    // 时间戳掩码
    private final long timestampMask = ~((-1L << (sequenceBits + workerBits + timestampBits)) | sequenceMask | workerMask);

    public SnowFlake(Long workerId) throws IllegalArgumentException {
        if (workerId > maxWorker || workerId < 0)
            throw new IllegalArgumentException("workerId不能大于" + maxWorker + "，也不能小于0");
        this.workerId = workerId;
    }

    public SnowFlake() {
    }

    public synchronized long nextId() {
        long ts = System.currentTimeMillis();

        if (ts == timestamp) {
            if (++sequenceId > maxSequence) {
                while (ts == timestamp) {
                    timestamp = System.currentTimeMillis();
                }
                sequenceId = 0;
            }
        } else {
            timestamp = ts;
            sequenceId = 0;
        }
        return ((timestamp - startTime) << (sequenceBits + workerBits) & timestampMask) |
                ((workerId << sequenceBits) & workerMask) | (sequenceId & sequenceMask);
    }
}
